import threading
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed, TimeoutError
from typing import List, Dict

import multiprocessing
from account.jie_account_service import JieAccountService
import spider_config
from common.convert import result2dbmodel
from common.logger import logger
from database.park_record_table import ParkRecordTable
from database.task_table import TaskTable
from database.task_record_table import TaskRecordsTable
from manager.proxy_manager import ProxyManager
from manager.spider_manager import SpiderManager
from manager.account_manager import AccountManager
from model.car_number import CarNumber
from model.dbmodel import DbTask, DbTaskRecord, DbParkRecord, TaskStatus
from model.result import Result
from model.error import ParkSpiderError, ParkSpiderErrorCode
from common.verify import verify_car_number
import signal
import requests
import time
from threading import Timer

import sys
sys.path.append("..") 
import spider_handler

import requests

from common.os import kill_process, kill_process_self, is_alive

task_lock = threading.RLock()

taskid_process_dict = {}

class TaskManager:

    def is_running(self, task_id: int) -> bool:
        return task_id in taskid_process_dict and is_alive(taskid_process_dict[task_id])

    def update_status(self, task_id: int, status: int):
        with TaskTable() as taskdb:
            taskdb.update_status(task_id, status)
            taskdb.commit()

    def start_spider_round(self, task: DbTask, car_numbers: List[CarNumber], spider_manager: SpiderManager):
        thread_pool = ThreadPoolExecutor(max_workers=task.threads)

        futures = []
        for number in car_numbers:
            futures.append(thread_pool.submit(spider_manager.query, number))
        success_count = 0
        
        wait_time = 30
        
        with ParkRecordTable() as db:
            for future in futures:
                try:
                    r: Result = future.result(timeout=wait_time)
                except TimeoutError:
                    logger.warning(f"任务 [{task.id}] 查询超时")
                    continue
                if r and r.success:
                    db.insert(result2dbmodel(task, r))
                    db.commit()
                    # logger.success(
                    #     f"查询成功: {r.car_number}，{r.park_name}, {r.platform.name}"
                    # )
                    success_count += 1
        
        return success_count

    def start_spider(
        self,
        task: DbTask,
        car_numbers: List[CarNumber],
        account_manager: AccountManager,
        proxy_manager: ProxyManager,
    ):
        try:
            task_record = DbTaskRecord()
            task_record.task_id = task.id
            task_record.user_id = task.user_id

            spider_manager = SpiderManager()
            spider_manager.set_platform(task.platform_id)
            account_manager.active_service(task.platform_id)

            spider_manager.set_account_manager(account_manager)
            spider_manager.set_proxym_anager(proxy_manager)

            total = len(car_numbers)

            round = 1

            while True:
                with TaskRecordsTable() as db:
                    task_record.content = f"开始执行，第 {round} 轮, 可用账号数量: {account_manager.account_count(task.platform_id)}"
                    logger.info(task_record.content)
                    db.insert(task_record, True)
                start_time = time.time()
                success_count = self.start_spider_round(task, car_numbers, spider_manager)
                with TaskRecordsTable() as db:
                    task_record.content = f"执行完成，第 {round} 轮: 耗时 {int(time.time() - start_time)} 秒, 查询 {total} 个车牌, 成功 {success_count} 条"
                    logger.success(
                        f"执行{task.id}完成，第 {round} 轮: 耗时 {int(time.time() - start_time)} 秒, 查询 {total} 个车牌, 成功 {success_count} 条"
                    )
                    db.insert(task_record, True)
                # 间隔1秒重新开始
                time.sleep(1)
                round += 1

        except Exception as e:
            logger.exception(e)
            self.update_status(task.id, TaskStatus.Error)
            with TaskRecordsTable() as db:
                task_record.content = f"执行异常: {repr(e)}"
                logger.error(task_record.content)
                db.insert(task_record)

            kill_process_self()

    def build_car_number_list(self, task: DbTask) -> List[CarNumber]:
        car_numbers = []
        for number in task.car_numbers.split("\n"):
            if verify_car_number(number):
                car_numbers.append(CarNumber(number))
        return car_numbers

    def start_task(
        self,
        task: DbTask,
        account_manager: AccountManager,
        proxy_manager: ProxyManager,
    ):
        with task_lock:
            if self.is_running(task.id):
                logger.warning(f"任务 {task.id} 正在运行, 正在强制结束并启动...")
                kill_process(taskid_process_dict[task.id])
                
            car_numbers = self.build_car_number_list(task)
            total = len(car_numbers)
            
            logger.info(
                f"开始任务: {task.id}, 查询平台: {task.platform_id}, 车牌数量: {total}, 线程数量: {task.threads}, 代理方式: {task.proxy}"
            )
            process = multiprocessing.Process(
                target=self.start_spider,
                args=(task, car_numbers, account_manager, proxy_manager),
            )
            process.start()
            logger.info(f"启动子进程: {process.pid}")
            taskid_process_dict[task.id] = process.pid
            
            self.update_status(task.id, TaskStatus.Running)
            logger.success(f"任务状态更新为: {TaskStatus.Running}")

    def remove_task_process(self, taskid):
        with task_lock:
            if taskid in taskid_process_dict:
                logger.info(f"移除任务 {taskid} 的子进程: {taskid_process_dict[taskid]}")
                taskid_process_dict.pop(taskid)

    def stop_task(self, task: DbTask):
        with task_lock:
            if self.is_running(task.id):
                self.update_status(task.id, TaskStatus.Stop)
                logger.success(f"任务状态更新为: {TaskStatus.Stop}")
                pid = taskid_process_dict[task.id]
                kill_process(pid)
                self.remove_task_process(task.id)
                logger.info(f"killed pid: {pid}")
            else:
                raise ParkSpiderError(ParkSpiderErrorCode.TaskNotRunning, task.id)